//
//  RegistrationViewModel.swift
//  PorscheRegistration
//
//  Created by Jinzhu Liu on 2023/11/16.
//

import Foundation
import Combine
import UIKit

enum DataUploadError: Error {
    case unknow
    case noImageId
}

protocol RegistrationViewModelInputType {
    func start()
    func selectedImage(_ image: UIImage)
    func selectedAvatarColor(_ color: AvatarColor)
}

protocol RegistrationViewModelOutputType {
    var title: String { get }
    var showPhotoPicker: AnyPublisher<Void, Never> { get }
}

protocol RegistrationViewModelType {
    var input: RegistrationViewModelInputType { get }
    var output: RegistrationViewModelOutputType { get }
}

class RegistrationViewModel: ObservableObject,
                             RegistrationViewModelType {
    
    var input: RegistrationViewModelInputType { self }
    var output: RegistrationViewModelOutputType { self }
    
    var title: String = "Registration"
    var avatarCellViewModel = RegistrationAvatarCellViewModel()
    var colorCellViewModel = RegistrationColorCellViewModel()
    var buttonCellViewModel = RegistrationButtonCellViewModel()
    
    var firstNameCellViewModel  = RegistrationNameCellViewModel(title: "First Name")
    var lastNameCellViewModel   = RegistrationNameCellViewModel(title: "Last Name")
    var phoneNumCellViewModel   = RegistrationPhoneNumCellViewModel()
    var emailCellViewModel      = RegistrationEmailCellViewModel()
    
    @Published var cellViewModels: [RegistrationCellViewModelType]
    
    private var showPhotoPickerSubject: PassthroughSubject<Void, Never>
    var showPhotoPicker: AnyPublisher<Void, Never> {
        showPhotoPickerSubject.eraseToAnyPublisher()
    }
    private var cancelableSet = Set<AnyCancellable>()
    
    init() {
        cellViewModels = [RegistrationCellViewModelType]()
        showPhotoPickerSubject = PassthroughSubject<Void, Never>()
        
        setupCellModels()
    }
    
    private func setupCellModels() {
        avatarCellViewModel.output.showPhotoPickerPublisher.sink { [unowned self] _ in
            self.showPhotoPickerSubject.send(())
        }.store(in: &cancelableSet)
        
        buttonCellViewModel.output.submitDataPublisher.sink { [weak self] _ in
            self?.submitAction()
        }.store(in: &cancelableSet)
    }
    
    private func generateCellModelList() -> [RegistrationCellViewModelType] {

        return [
            avatarCellViewModel,
            firstNameCellViewModel,
            lastNameCellViewModel,
            phoneNumCellViewModel,
            emailCellViewModel,
            colorCellViewModel,
            buttonCellViewModel
        ]
    }
    
    private func submitAction() {
        uploadDatas()
    }
    
    private func uploadDatas() {
        if let imageData = avatarCellViewModel.output.image.pngData() {
            MockNetworkClient.uploadImageData(imageData)
                .flatMap({ [weak self] imageId -> AnyPublisher<Bool, any Error> in
                    guard let self = self else {
                        return Fail<Bool, Error>(error: DataUploadError.unknow)
                            .eraseToAnyPublisher()
                    }
                    
                    do {
                        let jsonData = try self.generateJSON(with: imageId)
                        return MockNetworkClient.uploadRegistData(jsonData)
                    } catch {
                        return Fail<Bool, Error>(error: error)
                            .eraseToAnyPublisher()
                    }
                })
                .sink { completion in
                    if case .failure(let error) = completion {
                        // TODO: Upload image data error
                    }
                } receiveValue: { success in
                    print("Upload success")
                }
                .store(in: &cancelableSet)
        } else {
            // TODO: Upload image data error
        }
    }
    
    private func generateJSON(with imageId: String) throws -> Data {
        let dataModel = RegistrationDataModel(imageId: imageId,
                              firstName: firstNameCellViewModel.textValue,
                              lastName: lastNameCellViewModel.textValue,
                              email: emailCellViewModel.textValue,
                              phoneNum: phoneNumCellViewModel.textValue,
                              color: UIColorToHex(avatarCellViewModel.color))
        let encoder = JSONEncoder()
        do {
            let jsonData = try encoder.encode(dataModel)
            return jsonData
        } catch {
            throw error
        }
            
    }
}

extension RegistrationViewModel: RegistrationViewModelInputType {
    func selectedAvatarColor(_ color: AvatarColor) {
        colorCellViewModel.input.setTextValue(text: color.name)
        avatarCellViewModel.input.updateColor(color.color)
    }
    
    func start() {
        cellViewModels = generateCellModelList()
    }
    
    func selectedImage(_ image: UIImage) {
        avatarCellViewModel.input.updateImage(image)
    }
}

extension RegistrationViewModel: RegistrationViewModelOutputType {

}

func UIColorToHex(_ color: UIColor) -> String {
    var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
    if color.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
        let rgb = UInt32(red * 255.0) << 16 | UInt32(green * 255.0) << 8 | UInt32(blue * 255.0)
        return String(format: "%06X", rgb)
    } else {
        return "Invalid color"
    }
}
